# following taken essentially verbatim from wikipedia
# http://en.wikipedia.org/wiki/FAT_file_system

fatOffsetInfo = [
    (0x00, 3, "jmp"),
    (0x03, 8, "oem"),
    (0x0b, 2, "bytes_per_sector"),
    (0x0d, 1, "sectors_per_cluster"),
    (0x0e, 2, "reserved_sectors"),
    (0x10, 1, "fat_count"),
    (0x11, 2, "max_root_dirs"),
    (0x13, 2, "total_sectors_1"),
    (0x15, 1, "media_descriptor"),
    (0x16, 2, "sectors_per_fat_12_16"),
    (0x18, 2, "sectors_per_track"),
    (0x1a, 2, "number_of_heads"),
    (0x1c, 4, "hidden_sectors"),
    (0x20, 4, "total_sectors_2"),
    (0x24, 4, "sectors_per_fat_32"),
    (0x28, 2, "flags"),
    (0x2a, 2, "version"),
    (0x2c, 4, "root_start_cluster"),
    (0x30, 2, "fs_info_sector"), 
    (0x32, 2, "boot_sector_copy"),
    (0x34, 12, "reserved"),
    (0x40, 1, "drive_number"),
    (0x41, 1, "reserved1"),
    (0x42, 1, "ex_boot_sig"),
    (0x43, 4, "serial_number"),
    (0x47, 11, "volume_label"),
    (0x52, 8, "fs_type"),
    (0x5a, 420, "boot_code"),
    (0x1fe, 2, "boot_sector_sig") ] 

dirEntryOffsetInfo = [
    (0x00, 8, "file_name"),
    (0x08, 3, "file_ext"),
    (0x0b, 1, "file_attributes"),
    (0x0c, 1, "dir_reserved"),
    (0x0d, 1, "create_time_fine"),
    (0x0e, 2, "create_time"),
    (0x10, 2, "create_date"),
    (0x12, 2, "last_access_date"),
    (0x14, 2, "high_cluster_bytes"),
    (0x16, 2, "last_modified_time"),
    (0x18, 2, "last_modified_date"),
    (0x1a, 2, "low_cluster_bytes"),
    (0x1c, 4, "file_size") ]


bootSigHexStr = '"boot_sector_sig(hex)=<<%x,%x>>" % (ord(b0[510]), ord(b0[511]))'
hexStrFmt = '"%s=(hex)<<%%s>>" %%" ".join([hex(ord(x)) for x in get_%s(b0)])'
def processOffsets(offlist, outfile, infoType) :
    funcs = {} 
    dumpFuncBuilder = []
    for (off, size, label) in offlist :
        if size in [1,2, 4] : 
            genFuncs(label, off, size, outfile)
            dumpFuncBuilder.append('"%s=%%d" %% get_%s(b0)' % (label, label))
            if label == "boot_sector_sig" :  # worth it to double check this 
                dumpFuncBuilder.append(bootSigHexStr) 
        else : 
            genCharFuncs(label,off,size, outfile)
            if label != "boot_code" :  # boot code is unprintable 
                dumpFuncBuilder.append('"%s=<<%%s>>"%%get_%s(b0)' % (label, label))
                dumpFuncBuilder.append( hexStrFmt % (label,label))
    outfile.write("\n") 
    outfile.write("def dump%sInfo(args) : \n" % infoType) 
    
    if infoType == "Fat" : 
        outfile.write( "    b0 = block(0)\n") 
    else :
        outfile.write("    b0 = args\n")  

    outfile.write( '    output.write("-------------------------------\\n")\n')
    outfile.write( '    output.write("Dumping %s info...\\n")\n' %infoType )
    for i in dumpFuncBuilder :
        outfile.write('    output.write("    " + %s + "\\n")\n' % i)


setterBase = """
def set_%s(val,block, blockNumber) :
    lstr = list(block)
    lstr[%d:%d]= hton(val,%d) 
    writeBlock(blockNumber, block)
"""

getterBase = """
def get_%s(str) :
    return ntoh(str[%d:%d],%d)
""" 

csetterBase = """
def set_%s(val,block, blockNumber) :
    lstr = list(block)
    lstr[%s:%s+%s]= val 
    writeBlock(blockNumber, block)
"""

cgetterBase = """
def get_%s(str) :
    return str[%s:%s+%s]
""" 

def genFuncs(name, offset, size, outfile) :
    setter = setterBase % (name, offset, offset+size, size)
    outfile.write(setter)
    getter = getterBase % (name, offset, offset+size, size)
    outfile.write(getter) 

def genCharFuncs(name, offset,size, outfile) :
    setter = csetterBase % (name, offset, offset, size) 
    outfile.write(setter) 
    getter = cgetterBase % (name, offset, offset, size) 
    outfile.write(getter)

def main() :
    outfile = open("autofuncs.py", "w") 
    processOffsets(fatOffsetInfo, outfile, "Fat")
    processOffsets(dirEntryOffsetInfo, outfile, "DirEntry") 

main()
